home *** CD-ROM | disk | FTP | other *** search
/ InterCD 2000 September / september_2000.iso / intercd / root / ^Linux / cfengine-1.5.3 / src / link.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-10-24  |  27.7 KB  |  1,202 lines

  1. /* cfengine for GNU
  2.  
  3.         Copyright (C) 1995
  4.         Free Software Foundation, Inc.
  5.  
  6.    This file is part of GNU cfengine - written and maintained
  7.    by Mark Burgess, Dept of Computing and Engineering, Oslo College,
  8.    Dept. of Theoretical physics, University of Oslo
  9.  
  10.    This program is free software; you can redistribute it and/or modify it
  11.    under the terms of the GNU General Public License as published by the
  12.    Free Software Foundation; either version 2, or (at your option) any
  13.    later version.
  14.  
  15.    This program is distributed in the hope that it will be useful,
  16.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  17.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  18.    GNU General Public License for more details.
  19.  
  20.   You should have received a copy of the GNU General Public License
  21.   along with this program; if not, write to the Free Software
  22.   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA
  23.  
  24. */
  25.  
  26.  
  27. #include "cf.defs.h"
  28. #include "cf.extern.h"
  29.  
  30.  
  31. /*********************************************************************/
  32. /* TOOLKIT : links                                                   */
  33. /*********************************************************************/
  34.  
  35. LinkChildFiles(from,to,type,inclusions,exclusions,copy,nofile,ptr)
  36.  
  37. char *from, *to;
  38. char type;
  39. struct Item *inclusions, *exclusions, *copy;
  40. short nofile;
  41. struct Link *ptr;
  42.  
  43. { DIR *dirh;
  44.   struct dirent *dirp;
  45.   char pcwdto[bufsize],pcwdfrom[bufsize];
  46.   struct stat statbuf;
  47.   int LinkFiles(), HardLinkFiles(), AbsoluteLink(), RelativeLink();
  48.   int (*linkfiles)();
  49.  
  50. Debug("LinkChildFiles(%s,%s)\n",from,to);
  51.   
  52. if (stat(to,&statbuf) == -1)
  53.    {
  54.    return(false);  /* no error warning, since the higher level routine uses this */
  55.    }
  56.  
  57. if ((dirh = opendir(to)) == NULL)
  58.    {
  59.    sprintf(OUTPUT,"Can't open directory %s\n",to);
  60.    CfLog(cferror,OUTPUT,"opendir");
  61.    return false;
  62.    }
  63.  
  64. for (dirp = readdir(dirh); dirp != NULL; dirp = readdir(dirh))
  65.    {
  66.    if (!SensibleFile(dirp->d_name,to,NULL))
  67.       {
  68.       continue;
  69.       }
  70.  
  71.    strcpy(pcwdto,to);                               /* Assemble pathnames */
  72.    AddSlash(pcwdto);
  73.  
  74.    if (BufferOverflow(pcwdto,dirp->d_name))
  75.       {
  76.       FatalError("Can't build filename in LinkChildFiles");
  77.       }
  78.    strcat(pcwdto,dirp->d_name);
  79.  
  80.    strcpy(pcwdfrom,from);
  81.    AddSlash(pcwdfrom);
  82.  
  83.   if (BufferOverflow(pcwdfrom,dirp->d_name))
  84.       {
  85.       FatalError("Can't build filename in LinkChildFiles");
  86.       }
  87.    strcat(pcwdfrom,dirp->d_name);
  88.    
  89.    switch (type)
  90.       {
  91.       case 's':
  92.                 linkfiles = LinkFiles;
  93.                 break;
  94.       case 'r':
  95.             linkfiles = RelativeLink;
  96.         break;
  97.       case 'a':
  98.             linkfiles = AbsoluteLink;
  99.                 break;
  100.       case 'h':
  101.                 linkfiles = HardLinkFiles;
  102.                 break;
  103.       default:
  104.                 printf("Internal error, link type was [%c]\n",type);
  105.                 continue;
  106.       }
  107.    
  108.    (*linkfiles)(pcwdfrom,pcwdto,inclusions,exclusions,copy,nofile,ptr);
  109.    }
  110.  
  111. closedir(dirh);
  112. return true;
  113. }
  114.  
  115. /*********************************************************************/
  116.  
  117. LinkChildren(path,type,rootstat,uid,gid,inclusions,exclusions,copy,nofile,ptr)
  118.  
  119.  
  120. /* --------------------------------------------------------------------
  121.    Here we try to break up the path into a part which will match the
  122.    last element of a mounted filesytem mountpoint and the remainder
  123.    after that. We parse the path backwards to get a math e.g.
  124.  
  125.    /fys/lib/emacs ->  lib /emacs
  126.                       fys /lib/emacs
  127.                           /fys/lib/emacs
  128.  
  129.    we try to match lib and fys to the binserver list e.g. /mn/anyon/fys
  130.    and hope for the best. If it doesn't match, tough! 
  131.    --------------------------------------------------------------------- */
  132.  
  133. char *path, type;
  134. struct stat *rootstat;
  135. uid_t uid;
  136. gid_t gid;
  137. struct Item *inclusions, *exclusions, *copy;
  138. short nofile;
  139. struct Link *ptr;
  140.  
  141. { char *sp;
  142.   char lastlink[bufsize],server[bufsize],from[bufsize],to[bufsize],relpath[bufsize];
  143.   char odir[bufsize];
  144.   DIR *dirh;
  145.   struct dirent *dirp;
  146.   struct stat statbuf;
  147.   int matched = false;
  148.   int LinkFiles(), HardLinkFiles(), AbsoluteLink(), RelativeLink();
  149.   int (*linkfiles)();
  150.  
  151. Debug("LinkChildren(%s)\n",path);
  152.   
  153. if (! S_ISDIR(rootstat->st_mode))
  154.    {
  155.    sprintf(OUTPUT,"File %s is not a directory: it has no children to link!\n",path);
  156.    CfLog(cferror,OUTPUT,"");
  157.    return;
  158.    }
  159.  
  160. Verbose("Linking the children of %s\n",path);
  161.  
  162. for (sp = path+strlen(path); sp != path-1; sp--)
  163.    {
  164.    if (*(sp-1) == '/')
  165.       {
  166.       relpath[0] = '\0';
  167.       sscanf(sp,"%[^/]%s", lastlink,relpath);
  168.  
  169.       if (MatchAFileSystem(server,lastlink))
  170.          {
  171.          strcpy(odir,server);
  172.  
  173.      if (BufferOverflow(odir,relpath))
  174.         {
  175.         FatalError("culprit: LinkChildren()");
  176.         }
  177.          strcat(odir,relpath);
  178.  
  179.          if ((dirh = opendir(odir)) == NULL)
  180.             {
  181.             sprintf(OUTPUT,"Can't open directory %s\n",path);
  182.         CfLog(cferror,OUTPUT,"opendir");
  183.             return;
  184.             }
  185.  
  186.          for (dirp = readdir(dirh); dirp != NULL; dirp = readdir(dirh))
  187.             {
  188.             if (!SensibleFile(dirp->d_name,odir,NULL))
  189.                {
  190.                continue;
  191.                } 
  192.  
  193.             strcpy(from,path);
  194.         AddSlash(from);
  195.         
  196.         if (BufferOverflow(from,dirp->d_name))
  197.            {
  198.            FatalError("culprit: LinkChildren()");
  199.            }
  200.         
  201.             strcat(from,dirp->d_name);
  202.         
  203.             strcpy(to,odir);
  204.             AddSlash(to);
  205.         
  206.         if (BufferOverflow(to,dirp->d_name))
  207.            {
  208.            FatalError("culprit: LinkChildren()");
  209.            }
  210.         
  211.             strcat(to,dirp->d_name);
  212.  
  213.             Debug2("LinkChild from = %s to = %s\n",from,to);
  214.  
  215.             if (stat(to,&statbuf) == -1)
  216.                {
  217.                continue;
  218.                }
  219.             else
  220.                {
  221.            switch (type)
  222.                   {
  223.                   case 's':
  224.                             linkfiles = LinkFiles;
  225.                             break;
  226.                   case 'r':
  227.                         linkfiles = RelativeLink;
  228.                     break;
  229.                   case 'a':
  230.                         linkfiles = AbsoluteLink;
  231.                             break;
  232.                   case 'h':
  233.                             linkfiles = HardLinkFiles;
  234.                             break;
  235.                   default:
  236.                             sprintf(OUTPUT,"Internal error, link type was [%c]\n",type);
  237.                 CfLog(cferror,OUTPUT,"");
  238.                             continue;
  239.                   }
  240.  
  241.            matched = (*linkfiles)(from,to,inclusions,exclusions,copy,nofile,ptr);
  242.  
  243.                if (matched && !DONTDO)
  244.          {
  245.                  chown(from,uid,gid);
  246.                  }
  247.                }
  248.             }
  249.  
  250.          if (matched) return;
  251.          }
  252.       }
  253.    }
  254.  
  255. sprintf(OUTPUT,"Couldn't link the children of %s to anything because no\n",path);
  256. CfLog(cferror,OUTPUT,""); 
  257. sprintf(OUTPUT,"file system was found to mirror it in the defined binservers list.\n");
  258. CfLog(cferror,OUTPUT,""); 
  259. }
  260.  
  261. /*********************************************************************/
  262.  
  263. RecursiveLink(lp,from,to,maxrecurse)
  264.  
  265. struct Link *lp;
  266. char *from, *to;
  267. int maxrecurse;
  268.  
  269. { struct stat statbuf;
  270.   DIR *dirh;
  271.   struct dirent *dirp;
  272.   char newfrom[bufsize];
  273.   char newto[bufsize];
  274.   void *bug_check;
  275.   int LinkFiles(), HardLinkFiles(), AbsoluteLink(), RelativeLink();
  276.   int (*linkfiles)();
  277.   
  278. if (maxrecurse == 0)  /* reached depth limit */
  279.    {
  280.    Debug2("MAXRECURSE ran out, quitting at level %s with endlist = %d\n",to,lp->next);
  281.    return false;
  282.    }
  283.  
  284. if (IgnoreFile(to,"",lp->ignores))
  285.    {
  286.    Verbose("%s: Ignoring directory %s\n",VPREFIX,from);
  287.    return false;
  288.    }
  289.  
  290. if (strlen(to) == 0)     /* Check for root dir */
  291.    {
  292.    to = "/";
  293.    }
  294.  
  295. bug_check = lp->next;
  296.  
  297. if ((dirh = opendir(to)) == NULL)
  298.    {
  299.    sprintf(OUTPUT,"Can't open directory [%s]\n",to);
  300.    CfLog(cferror,OUTPUT,"opendir");
  301.    return false;
  302.    }
  303.  
  304. if (lp->next != bug_check)
  305.    {
  306.    printf("%s: solaris BSD compat bug: opendir wrecked the heap memory!!",VPREFIX);
  307.    printf("%s: in copy to %s, using workaround...\n",VPREFIX,from);
  308.    lp->next = bug_check;
  309.    }
  310.  
  311. for (dirp = readdir(dirh); dirp != NULL; dirp = readdir(dirh))
  312.    {
  313.    if (!SensibleFile(dirp->d_name,to,NULL))
  314.       {
  315.       continue;
  316.       }
  317.  
  318.    if (IgnoreFile(to,dirp->d_name,lp->ignores))
  319.       {
  320.       continue;
  321.       }
  322.  
  323.    strcpy(newfrom,from);                                   /* Assemble pathname */
  324.    AddSlash(newfrom);
  325.    strcpy(newto,to);
  326.    AddSlash(newto);
  327.  
  328.    if (BufferOverflow(newfrom,dirp->d_name))
  329.       {
  330.       closedir(dirh);
  331.       return true;
  332.       }
  333.  
  334.    strcat(newfrom,dirp->d_name);
  335.  
  336.    if (BufferOverflow(newto,dirp->d_name))
  337.       {
  338.       closedir(dirh);
  339.       return true;
  340.       }
  341.  
  342.    strcat(newto,dirp->d_name);
  343.  
  344.    if (TRAVLINKS)
  345.       {
  346.       if (stat(newto,&statbuf) == -1)
  347.          {
  348.          sprintf(OUTPUT,"Can't stat %s\n",newto);
  349.      CfLog(cfverbose,OUTPUT,"");
  350.          continue;
  351.          }
  352.       }
  353.    else
  354.       {
  355.       if (lstat(newto,&statbuf) == -1)
  356.          {
  357.          sprintf(OUTPUT,"Can't stat %s\n",newto);
  358.      CfLog(cfverbose,OUTPUT,"");
  359.      
  360.      bzero(VBUFF,bufsize);
  361.          if (readlink(newto,VBUFF,bufsize) != -1)
  362.             {
  363.             Verbose("File is link to -> %s\n",VBUFF);
  364.             }
  365.          continue;
  366.          }
  367.       }
  368.  
  369.    if (S_ISDIR(statbuf.st_mode))
  370.       {
  371.       RecursiveLink(lp,newfrom,newto,maxrecurse-1);
  372.       }
  373.    else
  374.       {
  375.       switch (lp->type)
  376.      {
  377.      case 's':
  378.                    linkfiles = LinkFiles;
  379.                    break;
  380.          case 'r':
  381.                linkfiles = RelativeLink;
  382.            break;
  383.          case 'a':
  384.                linkfiles = AbsoluteLink;
  385.                    break;
  386.          case 'h':
  387.                    linkfiles = HardLinkFiles;
  388.                    break;
  389.          default:
  390.                    printf("cfengine: internal error, link type was [%c]\n",lp->type);
  391.                    continue;
  392.      }
  393.  
  394.       (*linkfiles)(newfrom,newto,lp->inclusions,lp->exclusions,lp->copy,lp->nofile,lp);
  395.       }
  396.    }
  397.  
  398. closedir(dirh);
  399. return true;
  400. }
  401.  
  402. /*********************************************************************/
  403.  
  404. LinkFiles(from,to_tmp,inclusions,exclusions,copy,nofile,ptr)  /* should return true if 'to' found */
  405.  
  406. char *from, *to_tmp;
  407. struct Item *inclusions, *exclusions, *copy;
  408. short nofile;
  409. struct Link *ptr;
  410.  
  411. { struct stat buf,savebuf;
  412.   char to[bufsize],linkbuf[bufsize], saved[bufsize], absto[bufsize], *sp, *lastnode;
  413.   struct UidList fakeuid;
  414.   struct Image ip;
  415.  
  416. bzero(to,bufsize);
  417.   
  418. if ((*to_tmp != '/') && (*to_tmp != '.'))  /* links without a directory reference */
  419.    {
  420.    strcpy(to,"./");
  421.    }
  422.  
  423. if (strlen(to_tmp)+3 > bufsize)
  424.    {
  425.    printf("%s: bufsize boundaries exceeded in LinkFiles(%s->%s)\n",VPREFIX,from,to_tmp);
  426.    return false;
  427.    }
  428.  
  429. strcat(to,to_tmp);
  430.   
  431. Debug2("Linkfiles(%s,%s)\n",from,to);
  432.  
  433. for (lastnode = from+strlen(from); *lastnode != '/'; lastnode--)
  434.    {
  435.    }
  436.  
  437. lastnode++;
  438.  
  439. if (IgnoredOrExcluded(links,lastnode,inclusions,exclusions))
  440.    {
  441.    Verbose("%s: Skipping non-included pattern %s\n",VPREFIX,from);
  442.    return true;
  443.    }
  444.  
  445. if (IsWildItemIn(VCOPYLINKS,lastnode) || IsWildItemIn(copy,lastnode))
  446.    {
  447.    fakeuid.uid = sameowner;
  448.    fakeuid.next = NULL;
  449.    ip.plus = samemode;
  450.    ip.minus = samemode;
  451.    ip.uid = &fakeuid;
  452.    ip.gid = (struct GidList *) &fakeuid;
  453.    ip.action = "do";
  454.    ip.recurse = 0;
  455.    ip.type = 't';
  456.    ip.backup = true;
  457.    ip.exclusions = NULL;
  458.    ip.inclusions = NULL;
  459.    ip.symlink = NULL;
  460.    ip.classes = NULL;
  461.    ip.plus_flags = 0;
  462.    ip.minus_flags = 0;
  463.    ip.server = strdup("localhost");
  464.    Verbose("%s: Link item %s marked for copying instead\n",VPREFIX,from);
  465.    MakeDirectoriesFor(to);
  466.    CheckImage(to,from,&ip);
  467.    free(ip.server);
  468.    return true;
  469.    }
  470.  
  471. if (*to != '/')         /* relative path, must still check if exists */
  472.    {
  473.    Debug("Relative link destination detected: %s\n",to);
  474.    strcpy(absto,AbsLinkPath(from,to));
  475.    Debug("Absolute path to relative link = %s, from %s\n",absto,from);
  476.    }
  477. else
  478.    {
  479.    strcpy(absto,to);
  480.    }
  481.  
  482. if (stat(absto,&buf) == -1)
  483.    {
  484.    if (nofile)
  485.       {
  486.       Verbose("%s: (Force non-existent file link)\n",VPREFIX);
  487.       }
  488.    else
  489.       {
  490.       return(false);  /* no error warning, since the higher level routine uses this */
  491.       }
  492.    }
  493.  
  494. Debug2("Trying to link %s -> %s (%s)\n",from,to,absto);
  495.  
  496. if (lstat(from,&buf) == 0)
  497.    {
  498.    if (! S_ISLNK(buf.st_mode) && ! ENFORCELINKS)
  499.       {
  500.       sprintf(OUTPUT,"Error linking %s -> %s\n",from,to);
  501.       CfLog(cfsilent,OUTPUT,"");
  502.       sprintf(OUTPUT,"Cannot make link: %s exists and is not a link! (uid %d)\n",from,buf.st_uid);
  503.       CfLog(cfsilent,OUTPUT,"");
  504.       return(true);
  505.       }
  506.  
  507.    if (S_ISREG(buf.st_mode) && ENFORCELINKS)
  508.       {
  509.       sprintf(OUTPUT,"Moving %s to %s%s\n",from,from,CF_SAVED);
  510.       CfLog(cfsilent,OUTPUT,"");
  511.  
  512.       if (DONTDO)
  513.          {
  514.          return true;
  515.          }
  516.  
  517.       saved[0] = '\0';
  518.       strcpy(saved,from);
  519.       strcat(saved,CF_SAVED);
  520.  
  521.       if (rename(from,saved) == -1)
  522.          {
  523.          sprintf(OUTPUT,"Can't rename %s to %s\n",from,saved);
  524.      CfLog(cferror,OUTPUT,"rename");
  525.          return(true);
  526.          }
  527.  
  528.       if (Repository(saved))
  529.      {
  530.      unlink(saved);
  531.      }
  532.       }
  533.  
  534.    if (S_ISDIR(buf.st_mode) && ENFORCELINKS)
  535.       {
  536.       sprintf(OUTPUT,"Moving directory %s to %s%s.dir\n",from,from,CF_SAVED);
  537.       CfLog(cfsilent,OUTPUT,"");
  538.  
  539.       if (DONTDO)
  540.          {
  541.          return true;
  542.          }
  543.  
  544.       saved[0] = '\0';
  545.       strcpy(saved,from);
  546.       strcat(saved,CF_SAVED);
  547.       strcat(saved,".dir");
  548.  
  549.       if (stat(saved,&savebuf) != -1)
  550.      {
  551.      sprintf(OUTPUT,"Couldn't save directory %s, since %s exists already\n",from,saved);
  552.      CfLog(cferror,OUTPUT,"");
  553.      sprintf(OUTPUT,"Unable to force link to existing directory %s\n",from);
  554.      CfLog(cferror,OUTPUT,"");
  555.      return true;
  556.      }
  557.  
  558.       if (rename(from,saved) == -1)
  559.          {
  560.          sprintf(OUTPUT,"Can't rename %s to %s\n",from,saved);
  561.      CfLog(cferror,OUTPUT,"rename");
  562.          return(true);
  563.          }
  564.       }
  565.    }
  566.  
  567. bzero(linkbuf,bufsize);
  568.  
  569. if (readlink(from,linkbuf,bufsize) == -1)
  570.    {
  571.    if (! MakeDirectoriesFor(from))                  /* link doesn't exist */
  572.       {
  573.       sprintf(OUTPUT,"Couldn't build directory tree up to %s!\n",from);
  574.       CfLog(cfsilent,OUTPUT,"");
  575.       sprintf(OUTPUT,"One element was a plain file, not a directory!\n");
  576.       CfLog(cfsilent,OUTPUT,"");      
  577.       return(true);
  578.       }
  579.    }
  580. else
  581.    { int off1 = 0, off2 = 0;
  582.  
  583.    DeleteSlash(linkbuf);
  584.    
  585.    if (strncmp(linkbuf,"./",2) == 0)   /* Ignore ./ at beginning */
  586.       {
  587.       off1 = 2;
  588.       }
  589.  
  590.    if (strncmp(to,"./",2) == 0)
  591.       {
  592.       off2 = 2;
  593.       }
  594.    
  595.    if (strcmp(linkbuf+off1,to+off2) != 0)
  596.       {
  597.       if (ENFORCELINKS)
  598.          {
  599.          sprintf(OUTPUT,"Removing link %s\n",from);
  600.      CfLog(cfsilent,OUTPUT,"");
  601.  
  602.          if (!DONTDO)
  603.             {
  604.             if (unlink(from) == -1)
  605.                {
  606.                perror("unlink");
  607.                return true;
  608.                }
  609.  
  610.             return DoLink(from,to,ptr->defines);
  611.             }
  612.          }
  613.       else
  614.          {
  615.          sprintf(OUTPUT,"Old link %s points somewhere else. Doing nothing!\n",from);
  616.      CfLog(cfsilent,OUTPUT,"");
  617.          sprintf(OUTPUT,"(Link points to %s not %s)\n\n",linkbuf,to);
  618.      CfLog(cfsilent,OUTPUT,"");     
  619.          return(true);
  620.          }
  621.       }
  622.    else
  623.       {
  624.       sprintf(OUTPUT,"Link (%s->%s) exists.\n",from,to_tmp);
  625.       CfLog(cfverbose,OUTPUT,"");
  626.  
  627.       if (!nofile)
  628.      {
  629.      KillOldLink(from);             /* Check whether link points somewhere */
  630.      }
  631.       return(true);
  632.       }
  633.    }
  634.  
  635. return DoLink(from,to,ptr->defines);
  636. }
  637.  
  638. /*********************************************************************/
  639.  
  640. RelativeLink(from,to,inclusions,exclusions,copy,nofile,ptr)
  641.  
  642. char *from, *to;
  643. struct Item *inclusions, *exclusions,*copy;
  644. short nofile;
  645. struct Link *ptr;
  646. /* global char LINKTO[] */
  647.  
  648. { char *sp, *commonto, *commonfrom, *lastnode;
  649.   char buff[bufsize];
  650.   int levels=0;
  651.   
  652. Debug2("RelativeLink(%s,%s)\n",from,to);
  653.  
  654. if (*to == '.')
  655.    {
  656.    return LinkFiles(from,to,inclusions,exclusions,copy,nofile,ptr);
  657.    }
  658.  
  659. if (!CompressPath(LINKTO,to))
  660.    {
  661.    sprintf(OUTPUT,"Failed to link %s to %s\n",from,to);
  662.    CfLog(cferror,OUTPUT,"");
  663.    return false;
  664.    }
  665.  
  666. commonto = LINKTO;
  667. commonfrom = from;
  668.  
  669. if (strcmp(commonto,commonfrom) == 0)
  670.    {
  671.    CfLog(cferror,"Can't link file to itself!\n","");
  672.    sprintf(OUTPUT,"(%s -> %s)\n",from,to);
  673.    CfLog(cferror,OUTPUT,"");
  674.    return false;
  675.    }
  676.  
  677. while (*commonto == *commonfrom)
  678.    {
  679.    commonto++;
  680.    commonfrom++;
  681.    }
  682.  
  683. while (!((*commonto == '/') && (*commonfrom == '/')))
  684.    {
  685.    commonto--;
  686.    commonfrom--;
  687.    }
  688.  
  689. commonto++; 
  690.  
  691. Debug("Commonto = %s, common from = %s\n",commonto,commonfrom); 
  692.  
  693. for (sp = commonfrom; *sp != '\0'; sp++)
  694.    {
  695.    if (*sp == '/')
  696.        {
  697.        levels++;
  698.        }
  699.    }
  700.  
  701. Debug("LEVELS = %d\n",levels);
  702.  
  703. bzero(buff,bufsize);
  704.  
  705. strcat(buff,"./");
  706.  
  707. while(--levels > 0)
  708.    {
  709.    if (BufferOverflow(buff,"../"))
  710.       {
  711.       return false;
  712.       }
  713.    
  714.    strcat(buff,"../");
  715.    }
  716.  
  717. if (BufferOverflow(buff,commonto))
  718.    {
  719.    return false;
  720.    }
  721.  
  722. strcat(buff,commonto);
  723.  
  724. return LinkFiles(from,buff,inclusions,exclusions,copy,nofile,ptr);
  725. }
  726.  
  727. /*********************************************************************/
  728.  
  729. AbsoluteLink(from,to,inclusions,exclusions,copy,nofile,ptr)
  730.  
  731. char *from, *to;
  732. struct Item *inclusions,*exclusions,*copy;
  733. short nofile;
  734. struct Link *ptr;
  735. /* global LINKTO */
  736.  
  737. { char absto[bufsize];
  738.   char expand[bufsize];
  739.   
  740. Debug2("AbsoluteLink(%s,%s)\n",from,to);
  741.  
  742. if (*to == '.')
  743.    {
  744.    strcpy(LINKTO,from);
  745.    ChopLastNode(LINKTO);
  746.    AddSlash(LINKTO);
  747.    strcat(LINKTO,to);
  748.    }
  749. else
  750.    {
  751.    strcpy(LINKTO,to);
  752.    }
  753.  
  754. CompressPath(absto,LINKTO);
  755.  
  756. expand[0] = '\0';
  757.  
  758. if (!ExpandLinks(expand,absto,0))  /* begin at level 1 and beam out at 15 */
  759.    {
  760.    CfLog(cferror,"Failed to make absolute link in\n","");
  761.    sprintf("%s: %s -> %s\n",from,to);
  762.    CfLog(cferror,OUTPUT,"");
  763.    return false;
  764.    }
  765. else
  766.    {
  767.    Debug2("ExpandLinks returned %s\n",expand);
  768.    }
  769.  
  770. CompressPath(LINKTO,expand);
  771.  
  772. return LinkFiles(from,LINKTO,inclusions,exclusions,copy,nofile,ptr);
  773. }
  774.  
  775. /*********************************************************************/
  776.  
  777. DoLink (from,to,defines)
  778.  
  779. char *from, *to, *defines;
  780.  
  781. {
  782. if (DONTDO)
  783.    {
  784.    printf("cfengine: Need to link files %s -> %s\n",from,to);
  785.    }
  786. else
  787.    {
  788.    sprintf(OUTPUT,"Linking files %s -> %s\n",from,to);
  789.    CfLog(cfinform,OUTPUT,"");
  790.  
  791.    if (symlink(to,from) == -1)
  792.       {
  793.       sprintf(OUTPUT,"Couldn't link %s to %s\n",to,from);
  794.       CfLog(cferror,OUTPUT,"symlink");
  795.       return false;
  796.       }
  797.    else
  798.       {
  799.       AddMultipleClasses(defines);
  800.       return true;
  801.       }
  802.    }
  803. }
  804.  
  805. /*********************************************************************/
  806.  
  807. KillOldLink(name)
  808.  
  809. char *name;
  810.  
  811. { char linkbuf[bufsize];
  812.   char linkpath[bufsize],*sp;
  813.   struct stat statbuf;
  814.   short i;
  815.  
  816. Debug("KillOldLink(%s)\n",name);
  817. bzero(linkbuf,bufsize);
  818. bzero(linkpath,bufsize); 
  819.  
  820. if (readlink(name,linkbuf,bufsize) == -1)
  821.    {
  822.    sprintf(OUTPUT,"(Can't read link %s while checking for deadlinks)\n",name);
  823.    CfLog(cfverbose,OUTPUT,"");
  824.    return;
  825.    }
  826.  
  827. if (linkbuf[0] != '/')
  828.    {
  829.    strcpy(linkpath,name);    /* Get path to link */
  830.  
  831.    for (sp = linkpath+strlen(linkpath); (*sp != '/') && (sp >= linkpath); sp-- )
  832.      {
  833.      *sp = '\0';
  834.      }
  835.    }
  836.  
  837. strcat(linkpath,linkbuf);
  838. CompressPath(VBUFF,linkpath); 
  839.  
  840. if (stat(VBUFF,&statbuf) == -1)               /* link points nowhere */
  841.    {
  842.    if (KILLOLDLINKS || DEBUG || D2)
  843.       {
  844.       sprintf(OUTPUT,"%s is a link which points to %s, but that file doesn't seem to exist\n",name,VBUFF);
  845.       CfLog(cfsilent,OUTPUT,"");
  846.       }
  847.  
  848.    if (KILLOLDLINKS)
  849.       {
  850.       sprintf(OUTPUT,"Removing dead link %s\n",name);
  851.       CfLog(cfinform,OUTPUT,"");
  852.  
  853.       if (! DONTDO)
  854.          {
  855.          unlink(name);  /* May not work on a client-mounted system ! */
  856.          }
  857.       }
  858.    }
  859. }
  860.  
  861. /*********************************************************************/
  862.  
  863. HardLinkFiles(from,to,inclusions,exclusions,copy,nofile,ptr)  /* should return true if 'to' found */
  864.  
  865. char *from, *to;
  866. struct Item *inclusions,*exclusions,*copy;
  867. struct Link *ptr;
  868.  
  869. { struct stat frombuf,tobuf;
  870.   char saved[bufsize], *lastnode;
  871.   struct UidList fakeuid;
  872.   struct Image ip;
  873.   
  874. for (lastnode = from+strlen(from); *lastnode != '/'; lastnode--)
  875.    {
  876.    }
  877.  
  878. lastnode++;
  879.  
  880. if (inclusions != NULL && !IsWildItemIn(inclusions,lastnode))
  881.    {
  882.    Verbose("%s: Skipping non-included pattern %s\n",VPREFIX,from);
  883.    return true;
  884.    }
  885.  
  886. if (IsWildItemIn(VEXCLUDELINK,lastnode) || IsWildItemIn(exclusions,lastnode))
  887.    {
  888.    Verbose("%s: Skipping excluded pattern %s\n",VPREFIX,from);
  889.    return true;
  890.    }
  891.  
  892. if (IsWildItemIn(VCOPYLINKS,lastnode) || IsWildItemIn(copy,lastnode))
  893.    {
  894.    fakeuid.uid = sameowner;
  895.    fakeuid.next = NULL;
  896.    ip.plus = samemode;
  897.    ip.minus = samemode;
  898.    ip.uid = &fakeuid;
  899.    ip.gid = (struct GidList *) &fakeuid;
  900.    ip.action = "do";
  901.    ip.recurse = 0;
  902.    ip.type = 't';
  903.    ip.backup = true;
  904.    ip.plus_flags = 0;
  905.    ip.minus_flags = 0;
  906.    ip.exclusions = NULL;
  907.    ip.symlink = NULL;
  908.    Verbose("%s: Link item %s marked for copying instead\n",VPREFIX,from);
  909.    CheckImage(to,from,&ip);
  910.    return true;
  911.    }
  912.  
  913. if (stat(to,&tobuf) == -1)
  914.    {
  915.    return(false);  /* no error warning, since the higher level routine uses this */
  916.    }
  917.  
  918. if (! S_ISREG(tobuf.st_mode))
  919.    {
  920.    sprintf(OUTPUT,"%s: will only hard link regular files and %s is not regular\n",VPREFIX,to);
  921.    CfLog(cfsilent,OUTPUT,"");
  922.    return true;
  923.    }
  924.  
  925. Debug2("Trying to (hard) link %s -> %s\n",from,to);
  926.  
  927. if (stat(from,&frombuf) == -1)
  928.    {
  929.    DoHardLink(from,to,ptr->defines);
  930.    return true;
  931.    }
  932.  
  933.     /* both files exist, but are they the same file? POSIX says  */
  934.     /* the files could be on different devices, but unix doesn't */
  935.     /* allow this behaviour so the tests below are theoretical...*/
  936.  
  937. if (frombuf.st_ino != tobuf.st_ino && frombuf.st_dev != frombuf.st_dev)
  938.    {
  939.    Verbose("If this is POSIX, unable to determine if %s is hard link is correct\n",from);
  940.    Verbose("since it points to a different filesystem!\n");
  941.  
  942.    if (frombuf.st_mode == tobuf.st_mode && frombuf.st_size == tobuf.st_size)
  943.       {
  944.       sprintf(OUTPUT,"Hard link (%s->%s) on different device APPEARS okay\n",from,to);
  945.       CfLog(cfverbose,OUTPUT,"");
  946.       return true;
  947.       }
  948.    }
  949.  
  950. if (frombuf.st_ino == tobuf.st_ino && frombuf.st_dev == frombuf.st_dev)
  951.    {
  952.    sprintf(OUTPUT,"Hard link (%s->%s) exists and is okay.\n",from,to);
  953.    CfLog(cfverbose,OUTPUT,"");
  954.    return true;
  955.    }
  956.  
  957. sprintf(OUTPUT,"%s does not appear to be a hard link to %s\n",from,to);
  958. CfLog(cfinform,OUTPUT,""); 
  959.  
  960. if (ENFORCELINKS)
  961.    {
  962.    sprintf(OUTPUT,"Moving %s to %s.%s\n",from,from,CF_SAVED);
  963.    CfLog(cfinform,OUTPUT,"");
  964.  
  965.    if (DONTDO)
  966.       {
  967.       return true;
  968.       }
  969.  
  970.    saved[0] = '\0';
  971.    strcpy(saved,from);
  972.    strcat(saved,CF_SAVED);
  973.  
  974.    if (rename(from,saved) == -1)
  975.       {
  976.       perror("rename");
  977.       return(true);
  978.       }
  979.  
  980.    DoHardLink(from,to,ptr->defines);
  981.    }
  982.  
  983. return(true);
  984. }
  985.  
  986. /*********************************************************************/
  987.  
  988. DoHardLink (from,to,defines)
  989.  
  990. char *from, *to, *defines;
  991.  
  992. {
  993. if (DONTDO)
  994.    {
  995.    printf("Hardlink files %s -> %s\n\n",from,to);
  996.    }
  997. else
  998.    {
  999.    sprintf(OUTPUT,"Hardlinking files %s -> %s\n",from,to);
  1000.    CfLog(cfsilent,OUTPUT,"");
  1001.  
  1002.    if (link(to,from) == -1)
  1003.       {
  1004.       CfLog(cferror,"","link");
  1005.       }
  1006.    else
  1007.       {
  1008.       AddMultipleClasses(defines);
  1009.       }
  1010.    }
  1011. }
  1012.  
  1013. /*********************************************************************/
  1014.  
  1015. ExpandLinks(dest,from,level)                            /* recursive */
  1016.  
  1017.   /* Expand a path contaning symbolic links, up to 4 levels  */
  1018.   /* of symbolic links and then beam out in a hurry !        */
  1019.  
  1020. char *dest, *from;
  1021. int level;
  1022.  
  1023. { char *sp, buff[bufsize];
  1024.   char node[maxlinksize];
  1025.   struct stat statbuf;
  1026.   int lastnode = false;
  1027.  
  1028. bzero(dest,bufsize);
  1029.  
  1030. Debug2("ExpandLinks(%s,%d)\n",from,level);
  1031.  
  1032. if (level >= maxlinklevel)
  1033.    {
  1034.    CfLog(cferror,"Too many levels of symbolic links to evaluate absolute path\n");
  1035.    return false;
  1036.    }
  1037.  
  1038. for (sp = from; *sp != '\0'; sp++)
  1039.    {
  1040.    if (*sp == '/')
  1041.       {
  1042.       continue;
  1043.       }
  1044.    
  1045.    sscanf(sp,"%[^/]",node);
  1046.    sp += strlen(node);
  1047.  
  1048.    if (*sp == '\0')
  1049.       {
  1050.       lastnode = true;
  1051.       }
  1052.    
  1053.    if (strcmp(node,".") == 0)
  1054.       {
  1055.       continue;
  1056.       }
  1057.  
  1058.    if (strcmp(node,"..") == 0)
  1059.       {
  1060.       if (! ChopLastNode(LINKTO))
  1061.      {
  1062.      Debug("cfengine: used .. beyond top of filesystem!\n");
  1063.      return false;
  1064.      }
  1065.       continue;
  1066.       }
  1067.    else
  1068.       {
  1069.       strcat(dest,"/");
  1070.       }
  1071.    
  1072.    strcat(dest,node);
  1073.  
  1074.    if (lstat(dest,&statbuf) == -1)  /* File doesn't exist so we can stop here */
  1075.       {
  1076.       sprintf(OUTPUT,"Can't stat %s in ExpandLinks\n",dest);
  1077.       CfLog(cferror,OUTPUT,"stat");
  1078.       return false;
  1079.       }
  1080.  
  1081.    if (S_ISLNK(statbuf.st_mode))
  1082.       {
  1083.       bzero(buff,bufsize);
  1084.       
  1085.       if (readlink(dest,buff,bufsize) == -1)
  1086.      {
  1087.      sprintf(OUTPUT,"Expand links can't stat %s\n",dest);
  1088.      CfLog(cferror,OUTPUT,"readlink");
  1089.      return false;
  1090.      }
  1091.       else
  1092.          {
  1093.          if (buff[0] == '.')
  1094.         {
  1095.             ChopLastNode(dest);
  1096.         AddSlash(dest);
  1097.         if (BufferOverflow(dest,buff))
  1098.            {
  1099.            return false;
  1100.            }
  1101.         strcat(dest,buff);
  1102.         }
  1103.          else if (buff[0] == '/')
  1104.         {
  1105.           strcpy(dest,buff);
  1106.         DeleteSlash(dest);
  1107.  
  1108.         if (strcmp(dest,from) == 0)
  1109.            {
  1110.            Debug2("No links to be expanded\n");
  1111.            return true;
  1112.            }
  1113.         
  1114.         if (!lastnode && !ExpandLinks(buff,dest,level+1))
  1115.            {
  1116.            return false;
  1117.            }
  1118.         }
  1119.      else
  1120.         {
  1121.         ChopLastNode(dest);
  1122.         AddSlash(dest);
  1123.         strcat(dest,buff);
  1124.         DeleteSlash(dest);
  1125.  
  1126.         if (strcmp(dest,from) == 0)
  1127.            {
  1128.            Debug2("No links to be expanded\n");
  1129.            return true;
  1130.            }
  1131.         
  1132.         bzero(buff,bufsize);
  1133.  
  1134.         if (!lastnode && !ExpandLinks(buff,dest,level+1))
  1135.            {
  1136.            return false;
  1137.            }        
  1138.         }
  1139.          }
  1140.       }
  1141.    }
  1142. return true;
  1143. }
  1144.  
  1145. /*********************************************************************/
  1146.  
  1147. char *AbsLinkPath (from,relto)
  1148.  
  1149. char *from, *relto;
  1150.  
  1151. /* Take an abolute source and a relative destination object
  1152.    and find the absolute name of the to object */
  1153.  
  1154. { char *sp;
  1155.   int pop = 1;
  1156.  
  1157. if (*relto == '/')
  1158.    {
  1159.    printf("Cfengine internal error: call to AbsLInkPath with absolute pathname\n");
  1160.    FatalError("");
  1161.    }
  1162.  
  1163. strcpy(DESTINATION,from);  /* reuse to save stack space */
  1164.  
  1165. for (sp = relto; *sp != '\0'; sp++)
  1166.    {
  1167.    if (strncmp(sp,"../",3) == 0)
  1168.       {
  1169.       pop++;
  1170.       sp += 2;
  1171.       continue;
  1172.       }
  1173.  
  1174.    if (strncmp(sp,"./",2) == 0)
  1175.       {
  1176.       sp += 1;
  1177.       continue;
  1178.       }
  1179.  
  1180.    break; /* real link */
  1181.    }
  1182.  
  1183. while (pop > 0)
  1184.     {
  1185.     ChopLastNode(DESTINATION);
  1186.     pop--;
  1187.     }
  1188.  
  1189. if (strlen(DESTINATION) == 0)
  1190.    {
  1191.    strcpy(DESTINATION,"/");
  1192.    }
  1193. else
  1194.    {
  1195.    AddSlash(DESTINATION);
  1196.    }
  1197.  
  1198. strcat(DESTINATION,sp);
  1199. Debug("Reconstructed absolute linkname = %s\n",DESTINATION);
  1200. return DESTINATION; 
  1201. }
  1202.